﻿using System.Windows;
using Monti.DragAndDrop.Adorners;
using Monti.Docking.Controls;
using System.ComponentModel;

namespace Monti.Docking
{
   /// <summary>
   /// Adorner for docking.
   /// </summary>
   internal class DockingAdorner : DragNDropAdorner, INotifyPropertyChanged
   {
      /// <summary>
      /// Displayed adornment.
      /// </summary>
      private readonly DockHintDisplay m_Adornment;

      private int m_RectRow;
      private int m_RectRowSpan = 1;
      private int m_RectColumn;
      private int m_RectColumnSpan = 1;
      private double m_Opacity;

      /// <summary>
      /// Event used to notify when a property has changed.
      /// </summary>
      public event PropertyChangedEventHandler PropertyChanged;

      /// <summary>
      /// Initializes a new docking adorner.
      /// </summary>
      /// <param name="adornedElement">Element hosting adorner.</param>
      public DockingAdorner (UIElement adornedElement)
         : base (adornedElement)
      {
         m_Adornment = new DockHintDisplay { DataContext = this };
      }

      /// <summary>
      /// Gets the adornment to display.
      /// </summary>
      protected override UIElement Adornment
      {
         get { return this.m_Adornment; }
      }

      /// <summary>
      /// Sets if the dock is at the tab or not.
      /// </summary>
      public bool DockTab
      {
         set
         {
            if (value)
            {
               this.RectRow = 0;
               this.RectColumn = 0;
               this.RectRowSpan = 3;
               this.RectColumnSpan = 3;
               this.DockHintOpacity = 0.5;
               this.AdornerLayer.Update ();
            }
            else
               this.HideDockHint ();
         }
      }

      /// <summary>
      /// Sets if the dock is at the top or not.
      /// </summary>
      public bool DockTop
      {
         set
         {
            if (value)
            {
               this.RectRow = 0;
               this.RectColumn = 0;
               this.RectRowSpan = 1;
               this.RectColumnSpan = 3;
               this.DockHintOpacity = 0.5;
               this.AdornerLayer.Update ();
            }
            else
               this.HideDockHint ();
         }
      }

      /// <summary>
      /// Sets if the dock is at the bottom or not.
      /// </summary>
      public bool DockBottom
      {
         set
         {
            if (value)
            {
               this.RectRow = 2;
               this.RectColumn = 0;
               this.RectRowSpan = 1;
               this.RectColumnSpan = 3;
               this.DockHintOpacity = 0.5;
               this.AdornerLayer.Update ();
            }
            else
               this.HideDockHint ();
         }
      }

      /// <summary>
      /// Sets if the dock is at the left or not.
      /// </summary>
      public bool DockLeft
      {
         set
         {
            if (value)
            {
               this.RectRow = 0;
               this.RectColumn = 0;
               this.RectRowSpan = 3;
               this.RectColumnSpan = 1;
               this.DockHintOpacity = 0.5;
               this.AdornerLayer.Update ();
            }
            else
               this.HideDockHint ();
         }
      }

      /// <summary>
      /// Sets if the dock is at the right or not.
      /// </summary>
      public bool DockRight
      {
         set
         {
            if (value)
            {
               this.RectRow = 0;
               this.RectColumn = 2;
               this.RectRowSpan = 3;
               this.RectColumnSpan = 1;
               this.DockHintOpacity = 0.5;
               this.AdornerLayer.Update ();
            }
            else
               this.HideDockHint ();
         }
      }

      /// <summary>
      /// Hides the dock hint.
      /// </summary>
      public void HideDockHint ()
      {
         this.DockHintOpacity = 0.0;
         this.AdornerLayer.Update ();
      }

      /// <summary>
      /// Gets or Sets the rect row.
      /// </summary>
      public int RectRow
      {
         get { return this.m_RectRow; }
         set
         {
            this.m_RectRow = value;
            this.RaisePropertyChanged ("RectRow");
         }
      }

      /// <summary>
      /// Gets or Sets the rect row span.
      /// </summary>
      public int RectRowSpan
      {
         get { return this.m_RectRowSpan; }
         set
         {
            this.m_RectRowSpan = value;
            this.RaisePropertyChanged ("RectRowSpan");
         }
      }

      /// <summary>
      /// Gets or Sets the rect column.
      /// </summary>
      public int RectColumn
      {
         get { return this.m_RectColumn; }
         set
         {
            this.m_RectColumn = value;
            this.RaisePropertyChanged ("RectColumn");
         }
      }

      /// <summary>
      /// Gets or Sets the rect column span.
      /// </summary>
      public int RectColumnSpan
      {
         get { return this.m_RectColumnSpan; }
         set
         {
            this.m_RectColumnSpan = value;
            this.RaisePropertyChanged ("RectColumnSpan");
         }
      }

      /// <summary>
      /// Gets or Sets the opacity for the dock hint.
      /// </summary>
      public double DockHintOpacity
      {
         get { return this.m_Opacity; }
         set
         {
            this.m_Opacity = value;
            this.RaisePropertyChanged ("DockHintOpacity");
         }
      }

      /// <summary>
      /// Raises the property changed event.
      /// </summary>
      /// <param name="propertyName">Name of property that has changed.</param>
      protected virtual void RaisePropertyChanged (string propertyName)
      {
         if (this.PropertyChanged != null)
            this.PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
      }
   }
}
